package main

import (
	"log"
	"reflect"
)

type user struct {
	Name  string
	Age   int
	Hobby []string
}
type outuser struct {
	Name  string
	Age   int
	Hobby []string
}

func userInfos() {
	u := user{Name: "kso", Age: 2222, Hobby: []string{"kso1", "kso2", "kso3"}}
	o := outuser{}
	error := copy(&o, u)
	if error != nil {
		log.Fatalln(error)
	}
	log.Printf("user:  %#v  ;;;;outuser:  %#v\n", u, o)

}
func copy(out interface{}, source interface{}) error {
	sourcetypeOf := reflect.TypeOf(source)
	sourcevalueOf := reflect.ValueOf(source)
	//如果为指针类型，则获取期值
	if sourcetypeOf.Kind() == reflect.Ptr {
		log.Println(" sourcetypeOf.Kind() == reflect.Ptr ")
		sourcetypeOf = sourcetypeOf.Elem()
		sourcevalueOf = sourcevalueOf.Elem()
	}
	log.Println(" source info : ", sourcetypeOf, sourcevalueOf)
	outtypeOf := reflect.TypeOf(out)
	outValueof := reflect.ValueOf(out)
	if outtypeOf.Kind() != reflect.Ptr {
		log.Fatalln("outtypeOf.Kind()  !=  reflect.Ptr指针类型")
	} else if outtypeOf.Kind() == reflect.Ptr {
		outtypeOf = outtypeOf.Elem()
		outValueof = outValueof.Elem()
		log.Println("outtypeOf.Kind() == reflect.Ptr ", outtypeOf, outValueof)
	}

	if outtypeOf.Kind() != reflect.Struct {
		log.Fatalln("outtypeOf reflect.Struct “目标对象必须为struct的指针")
	}
	if sourcetypeOf.Kind() != reflect.Struct {
		log.Fatalln("sourcevalueOf reflect.Struct “目标对象必须为struct的指针")
	}
	destObj := reflect.New(outtypeOf)
	for i := 0; i < outtypeOf.NumField(); i++ {
		destField := outtypeOf.Field(i)
		if sourceFilecd, ok := sourcetypeOf.FieldByName(destField.Name); ok {
			if destField.Type != sourceFilecd.Type {
				continue
			}
			log.Println("value : ", destField, sourceFilecd)

			value := sourcevalueOf.FieldByName(destField.Name)
			destObj.Elem().FieldByName(destField.Name).Set(value)
		}
	}
	outValueof.Set(destObj.Elem())
	return nil
}
